<script setup>
import {ref, onMounted, computed} from 'vue'
import { sessionApi, pageRoleApi, saveRoleApi, delRolesApi, oneRoleApi, selModApi } from '@/common/api'
import router from '@/common/router'
import Note from '@/components/notify'
import Msg from '@/components/message'
import Confirm from '@/components/confirm'
import { CScrollbar } from 'c-scrollbar'
import Pager from '@/components/pagination/UbtPager.vue'
import { formatDate } from '@/common/filter'

// 自动加载，判断权限
onMounted(() => {
  checkAuth()
})

const procAuth = ref({
  addAuth: false,
  delAuth: false,
  edtAuth: false
})
// checkAuth 获取权限
const checkAuth = async () => {
  const res = await sessionApi()
  if (res.code === 200) {
    const userBtnCode = res.data.btnCodes
    procAuth.value = {
      addAuth: userBtnCode.indexOf('1001010301') !== -1,
      delAuth: userBtnCode.indexOf('1001010302') !== -1,
      edtAuth: userBtnCode.indexOf('1001010303') !== -1
    }
    selMods()
    list(0, 1)
  } else {
    Msg({ kind: 'error', txt: res.msg })
    router.replace('/login')
  }
}

const schObj = {
  schName: '',
  offset: 0,
  limit: 20
}
const schRef = ref(schObj)
const total = ref(0)
const curPage = ref(1)
const roleList = ref([])
const hasData = ref(false)
const checkList = ref([])
// list 列表展示
const list = async (offset, cur) => {
  schRef.value.offset = offset || 0
  curPage.value = cur || 1
  hasData.value = false
  const res = await pageRoleApi(schRef.value)
  if(res.code === 200 && res.data) {
    hasData.value = true
    total.value = res.data.total
    roleList.value = res.data.list
    idList.value = []
    checkList.value = []
    allCheck.value = false
    res.data.list.forEach(() => {
      checkList.value.push(false)
    })
  }
}

// search 筛选
const schShow = ref(false)
const search = () => {
  schShow.value = !schShow.value
}

// clrSch 重置搜索框
const clrSch = () => {
  schRef.value = {
    schName: '',
    offset: 0,
    limit: 20
  }
  list(0, 1)
}

// 选择效果实现
const idList = ref([])
const allCheck = ref(false)
// checkAll 全选
const checkAll = () => {
  idList.value = []
  checkList.value = []
  allCheck.value = !allCheck.value
  if(allCheck.value) {
    roleList.value.forEach(item => {
      idList.value.push(item.roleId)
      checkList.value.push(true)
    })
  } else {
    roleList.value.forEach(() => {
      checkList.value.push(false)
    })
  }
}
// checkCurId 单选
const checkCurId = (idx, roleId) => {
  if(!checkList.value[idx]) {
    idList.value.push(roleId)
  } else {
    const index = idList.value.findIndex(id => {
      if (id === roleId) {
        return true
      }
    })
    idList.value.splice(index, 1)
  }
  checkList.value[idx] = !checkList.value[idx]
}

const roleObj = {
  roleId: '',
  roleName: '',
  roleCode: '',
  modCodes: '',
  btnCodes: ''
}
const roleForm = ref(roleObj)
// add 新增
const showModal = ref(false)
const add = () => {
  initVal()
  showModal.value = true
}
// update 修改
const update = async (roleId) => {
  const res = await oneRoleApi({roleId})
  if(res.code === 200) {
    roleForm.value = res.data
    modIdList.value = roleForm.value.modCodes.split(',')
    btnIdList.value = roleForm.value.btnCodes ? roleForm.value.btnCodes.split(',') : []
    initVal()
    showModal.value = true
  } else {
    Msg({ kind: 'info', txt: '暂无内容' })
  }
}
// save 保存提交
const save = async () => {
  roleForm.value.modCodes = modIdList.value.join(",")
  roleForm.value.btnCodes = btnIdList.value.join(",")
  let roleName = roleForm.value.roleName
  let roleCode = roleForm.value.roleCode
  let modCodes = roleForm.value.modCodes
  if(roleName === '' || roleName.length > 50) {
    Msg({ kind: 'warn', txt: '角色的名称不能为空，且长度不超过50个字符！' })
    return
  } else if(roleCode === '' || roleCode.length > 30) {
    Msg({ kind: 'warn', txt: '角色的编码不能为空，且长度为30位的数字编码！' })
    return
  } else if(modCodes === '' || modCodes.length < 8) {
    Msg({ kind: 'warn', txt: '操作模块不能为空！' })
    return
  }
  const res = await saveRoleApi(roleForm.value)
  if(res.code === 200) {
    closeModal()
    list(0, 1)
    Note({ kind: 'success', title: '成功', txt: '恭喜您，角色信息保存成功！' })
  } else {
    Msg({ kind: 'error', txt: res.msg })
  }
}

// 模块及按钮选中标识数组
const modChkList = ref([])
let btnChkList = []
// closeModal 关闭弹出层，并重置表单数据
const closeModal = () => {
  modChkList.value = []
  modIdList.value = []
  btnChkList = []
  btnIdList.value = []
  modAllChk.value = false
  showModal.value = false
  roleForm.value = {
    roleId: '',
    roleName: '',
    roleCode: '',
    modCodes: '',
    btnCodes: ''
  }
}

// deletes 删除角色
const deletes = async() => {
  if(!idList || idList.value.length===0) {
    Msg({ kind: 'warn', txt: '请至少选择一项再操作！' })
    return
  }
  Confirm('确定要删除选中的角色吗？').then(() => {
    delRole()
  }).catch(() => {
    Msg({ kind: 'info', txt: "取消处理选中的数据！" })
  })
}
// delRole 删除角色实现，分离出来防止调用时异步报错
const delRole = async () => {
  let roleIds = idList.value.join(',')
  const res = await delRolesApi({ roleIds })
  if(res.code === 200) {
    list(0, 1)
    Note({ kind: 'success', title: '成功', txt: '恭喜您，角色信息删除成功！' })
  } else {
    Msg({ kind: 'error', txt: res.msg })
  }
}

// fmtDate 时间戳转时间
const fmtDate = computed(() => {
  return (time, kind) => {
    let date = new Date(time*1000)
    return formatDate(date, kind)
  }
})

// 所有模块数组（包含按钮数组）
const modList = ref([])
// selMods 获取模块及按钮列表
const selMods = async (kind) => {
  const res = await selModApi()
  if(res.code === 200) {
    modList.value = res.data
  }
}

// initVal 初始化模块及按钮值选中
const initVal = () => {
  modList.value.forEach(curMod => {
    let modChked = roleForm.value.modCodes.indexOf(curMod.modCode) !== -1
    if(curMod.btnList && curMod.btnList.length>0) {
      btnChkList = []
      curMod.btnList.forEach(curBtn => {
        if(roleForm.value.btnCodes.indexOf(curBtn.btnCode) !== -1) {
          btnChkList.push(true)
        } else {
          btnChkList.push(false)
        }
      })
    }
    modChkList.value.push({
      chked: modChked,
      btnChkList: btnChkList
    })
  })
}

// 选中的模块及按钮编号数组
const modIdList = ref([])
const btnIdList = ref([])
// 全选标识
const modAllChk = ref(false)
// chkModAll 全选
const chkModAll = () => {
  modChkList.value = []
  modIdList.value = []
  btnIdList.value = []
  modAllChk.value = !modAllChk.value
  modList.value.forEach(curMod => {
    if(curMod.btnList && curMod.btnList.length>0) {
      btnChkList = []
      curMod.btnList.forEach(curBtn => {
        btnIdList.value.push(curBtn.btnCode)
        btnChkList.push(modAllChk.value)
      })
    }
    modIdList.value.push(curMod.modCode)
    modChkList.value.push({
      chked: modAllChk.value,
      btnChkList: btnChkList
    })
  })
  if(!modAllChk.value) {
    modIdList.value = []
    btnIdList.value = []
  }
}

// chkModId 单选模块
const chkModId = (idx, curMod) => {
  // 将模块选中数组中对应的标签置反
  modChkList.value[idx].chked = !modChkList.value[idx].chked
  if(modChkList.value[idx].chked) {
    // 选中，将对应的编码存储至模块编号数组中
    modIdList.value.push(curMod.modCode)
    if(curMod.btnList && curMod.btnList.length>0) {
      btnChkList = []
      curMod.btnList.forEach(curBtn => {
        btnIdList.value.push(curBtn.btnCode)
        btnChkList.push(true)
      })
      modChkList.value[idx] = {
        chked: true,
        btnChkList: btnChkList
      }
    }
  } else {
    // 没选中，查找到对应模块编码的索引
    // 删除索引对应的按钮编码
    if(curMod.btnList && curMod.btnList.length>0) {
      for(let i=0, c=curMod.btnList.length; i<c; i++) {
        if(!modChkList.value[idx].btnChkList[i]) {
          continue
        }
        const btnIdx = btnIdList.value.findIndex(btnCode => {
          if(btnCode === curMod.btnList[i].btnCode) {
            return true
          }
        })
        btnIdList.value.splice(btnIdx, 1)
      }
    }
    // 删除索引对应的模块编码
    modChkList.value[idx] = {
      chked: false,
      btnChkList: []
    }
    const modIdx = modIdList.value.findIndex(modCode => {
      if(modCode === curMod.modCode) {
        return true
      }
    })
    modIdList.value.splice(modIdx, 1)
  }
}
// chkBtnId 单选按钮
const chkBtnId = (index, idx, curBtn) => {
  btnChkList = modChkList.value[index].btnChkList
  // 将模块选中数组中对应的标签置反
  btnChkList[idx] = !btnChkList[idx]
  if(btnChkList[idx]) {
    // 选中，将对应的编码存储至模块编号数组中
    btnIdList.value.push(curBtn.btnCode)
    btnChkList.push(true)
  } else {
    // 没选中，查找到对应模块编码的索引
    const btnIdx = btnIdList.value.findIndex(btnCode => {
      if(btnCode === curBtn.btnCode) {
        return true
      }
    })
    btnIdList.value.splice(btnIdx, 1)
  }
}
</script>

<template>
  <div class="a">
    <!-- 头部角色 -->
    <div class="b">
      <div v-if="procAuth.addAuth" class="btn-p" title="新增" @click="add()"><i class="iconfont doc_text"></i> 新增</div>
      <div v-if="procAuth.delAuth" class="btn-d" title="删除" @click="deletes()"><i class="iconfont trash"></i> 删除</div>
      <div class="btn-r" title="筛选" @click="search()"><i class="iconfont search"></i></div>
      <div class="btn-r" title="刷新" @click="list(0, 1)"><i class="iconfont arrow__circlepath"></i></div>
    </div>
    <!-- 中部数据 -->
    <div class="c" v-if="schShow">
      <div class="d"><input type="text" v-model="schRef.schName" placeholder="请输入名称或编码的关键字" class="e" /></div>
      <div class="btn-p" @click="list(0, 1)"><i class="iconfont search"></i> 筛选</div>
      <div class="btn-d" @click="clrSch()"><i class="iconfont arrowshape_turn_up_left"></i> 重置</div>
    </div>
    <div class="f" v-if="hasData">
      <table>
        <tr>
          <th style="width: 10%;"><i @click="checkAll()" :class="['iconfont', allCheck ? 'checkmark_square_fill chked' : 'app chk']"></i></th>
          <th style="width: 25%;">名称</th>
          <th style="width: 20%;">编码</th>
          <th style="width: 25%;">时间</th>
          <th style="width: 20%;">操作</th>
        </tr>
        <tr v-for="(curRole, index) in roleList" :key="curRole.roleId" class="tr-style">
          <td class="txt-center"><i @click="checkCurId(index, curRole.roleId)" :class="['iconfont', checkList[index] ? 'checkmark_square_fill chked' : 'app chk']"></i></td>
          <td>{{curRole.roleName}}</td>
          <td class="txt-center">{{curRole.roleCode}}</td>
          <td class="txt-center">{{fmtDate(curRole.addTime, 2)}}</td>
          <td class="txt-center">
            <span v-if="procAuth.edtAuth" class="cl-blue" title="修改" @click="update(curRole.roleId)"><i class="iconfont square_pencil"></i> 修 改</span>
          </td>
        </tr>
      </table>
      <Pager v-if="hasData" :limit="schRef.limit" :total="total" :page="curPage" @turn="list" />
    </div>
    <div v-else class="no-data">暂无内容</div>

    <!-- 新增、修改弹出层 -->
    <transition name="fade-mod" appear>
      <div v-if="showModal" class="modal-backdrop">
        <c-scrollbar>
          <div class="modal" style="width: 800px;">
            <div class="modal-header">
              <div class="header-left"><i class="iconfont doc_plaintext fs20"></i> 保存角色信息</div>
              <div class="header-right" @click="closeModal()"><i class="iconfont xmark fs20"></i></div>
            </div>
            <div class="modal-body">
              <div>
                <div class="ipt-title"><span class="required">*</span>角色名称</div>
                <div><input type="text" v-model="roleForm.roleName" maxlength="50" placeholder="请输入角色名称" class="txt" /></div>
              </div>
              <div>
                <div class="ipt-title"><span class="required">*</span>角色编码</div>
                <div><input type="text" v-model="roleForm.roleCode" maxlength="30" placeholder="请输入角色编码" class="txt" /></div>
              </div>
              <div>
                <div class="ipt-title"><span class="required">*</span>权限配置</div>
                <div>
                  <table>
                    <tr>
                      <th style="width: 40%;"><i @click="chkModAll()" :class="['iconfont', modAllChk ? 'checkmark_square_fill chked' : 'app chk']"> 模块名称</i></th>
                      <th style="width: 60%;">操作按钮</th>
                    </tr>
                    <tr v-for="(curMod, index) in modList" :key="curMod.modId" class="tr-style">
                      <td>
                        <div :style="{'padding-left': curMod.modLevel*20+'px'}"><i @click="chkModId(index, curMod)" :class="['iconfont', modChkList[index].chked ? 'checkmark_square_fill chked' : 'app chk']"></i> {{curMod.modName}}[{{curMod.modCode}}]</div>
                      </td>
                      <td>
                        <span v-for="(curBtn, idx) in curMod.btnList" :key="curBtn.btnId" class="g"><i @click="chkBtnId(index, idx, curBtn)" :class="['iconfont', modChkList[index].btnChkList[idx] ? 'checkmark_square_fill chked' : 'app chk']"></i> {{curBtn.btnName}}</span>
                      </td>
                    </tr>
                  </table>
                </div>
              </div>
            </div>
            <div class="modal-footer">
              <div class="btn-p" @click="save()"><i class="iconfont today_fill"></i> 保存</div>
              <div class="btn-d" @click="closeModal()"><i class="iconfont arrowshape_turn_up_left"></i> 取消</div>
            </div>
          </div>
        </c-scrollbar>
      </div>
    </transition>
  </div>
</template>

<style scoped>
.a {width: 100%; height: 100%;}
.b {padding: 10px 20px; display: flex; display: -webkit-flex;}
.c {margin: 0 10px 10px 10px; border: 1px solid #CCC; display: flex; display: -webkit-flex; padding: 15px;}
.d {flex-grow: 1;}
.e {width: 230px; padding: 8px;}
.f {background-color: #FFF;}
.g {padding-right: 20px;}
</style>
